#define JPEG_INTERNALS
#include "jinclude.h"
#include "jpeglib.h"

void jpeg_CreateCompress( j_compress_ptr cinfo, int version, size_t structsize ) {
  int i;
  cinfo->mem = NULL;		/* so jpeg_destroy knows mem mgr not called */
  if( version != JPEG_LIB_VERSION )
  { ERREXIT2( cinfo, JERR_BAD_LIB_VERSION, JPEG_LIB_VERSION, version ); }
  if( structsize != SIZEOF( struct jpeg_compress_struct ) )
    ERREXIT2( cinfo, JERR_BAD_STRUCT_SIZE,
              ( int ) SIZEOF( struct jpeg_compress_struct ), ( int ) structsize );
  {
    struct jpeg_error_mgr * err = cinfo->err;
    void * client_data = cinfo->client_data; /* ignore Purify complaint here */
    MEMZERO( cinfo, SIZEOF( struct jpeg_compress_struct ) );
    cinfo->err = err;
    cinfo->client_data = client_data;
  }
  cinfo->is_decompressor = FALSE;
  /* Initialize a memory manager instance for this object */
  jinit_memory_mgr( ( j_common_ptr ) cinfo );
  /* Zero out pointers to permanent structures. */
  cinfo->progress = NULL;
  cinfo->dest = NULL;
  cinfo->comp_info = NULL;
  for( i = 0; i < NUM_QUANT_TBLS; i++ )
  { cinfo->quant_tbl_ptrs[i] = NULL; }
  for( i = 0; i < NUM_HUFF_TBLS; i++ ) {
    cinfo->dc_huff_tbl_ptrs[i] = NULL;
    cinfo->ac_huff_tbl_ptrs[i] = NULL;
  }
  cinfo->script_space = NULL;
  cinfo->input_gamma = 1.0;	/* in case application forgets */
  /* OK, I'm ready */
  cinfo->global_state = CSTATE_START;
}


/*
   Destruction of a JPEG compression object
*/

void jpeg_destroy_compress( j_compress_ptr cinfo ) {
  jpeg_destroy( ( j_common_ptr ) cinfo ); /* use common routine */
}


void jpeg_abort_compress( j_compress_ptr cinfo ) {
  jpeg_abort( ( j_common_ptr ) cinfo ); /* use common routine */
}

void jpeg_suppress_tables( j_compress_ptr cinfo, wxjpeg_boolean suppress ) {
  int i;
  JQUANT_TBL * qtbl;
  JHUFF_TBL * htbl;
  for( i = 0; i < NUM_QUANT_TBLS; i++ ) {
    if( ( qtbl = cinfo->quant_tbl_ptrs[i] ) != NULL )
    { qtbl->sent_table = suppress; }
  }
  for( i = 0; i < NUM_HUFF_TBLS; i++ ) {
    if( ( htbl = cinfo->dc_huff_tbl_ptrs[i] ) != NULL )
    { htbl->sent_table = suppress; }
    if( ( htbl = cinfo->ac_huff_tbl_ptrs[i] ) != NULL )
    { htbl->sent_table = suppress; }
  }
}


void jpeg_finish_compress( j_compress_ptr cinfo ) {
  JDIMENSION iMCU_row;
  if( cinfo->global_state == CSTATE_SCANNING ||
      cinfo->global_state == CSTATE_RAW_OK ) {
    /* Terminate first pass */
    if( cinfo->next_scanline < cinfo->image_height )
    { ERREXIT( cinfo, JERR_TOO_LITTLE_DATA ); }
    ( *cinfo->master->finish_pass )( cinfo );
  } else if( cinfo->global_state != CSTATE_WRCOEFS )
  { ERREXIT1( cinfo, JERR_BAD_STATE, cinfo->global_state ); }
  /* Perform any remaining passes */
  while( ! cinfo->master->is_last_pass ) {
    ( *cinfo->master->prepare_for_pass )( cinfo );
    for( iMCU_row = 0; iMCU_row < cinfo->total_iMCU_rows; iMCU_row++ ) {
      if( cinfo->progress != NULL ) {
        cinfo->progress->pass_counter = ( long ) iMCU_row;
        cinfo->progress->pass_limit = ( long ) cinfo->total_iMCU_rows;
        ( *cinfo->progress->progress_monitor )( ( j_common_ptr ) cinfo );
      }
      /* We bypass the main controller and invoke coef controller directly;
         all work is being done from the coefficient buffer.
      */
      if( !( *cinfo->coef->compress_data )( cinfo, ( JSAMPIMAGE ) NULL ) ) {
        ERREXIT( cinfo, JERR_CANT_SUSPEND );
      }
    }
    ( *cinfo->master->finish_pass )( cinfo );
  }
  /* Write EOI, do final cleanup */
  ( *cinfo->marker->write_file_trailer )( cinfo );
  ( *cinfo->dest->term_destination )( cinfo );
  /* We can use jpeg_abort to release memory and reset global_state */
  jpeg_abort( ( j_common_ptr ) cinfo );
}

void jpeg_write_marker( j_compress_ptr cinfo, int marker,
                        const JOCTET *dataptr, unsigned int datalen ) {
  JMETHOD( void, write_marker_byte, ( j_compress_ptr info, int val ) );
  if( cinfo->next_scanline != 0 ||
      ( cinfo->global_state != CSTATE_SCANNING &&
        cinfo->global_state != CSTATE_RAW_OK &&
        cinfo->global_state != CSTATE_WRCOEFS ) )
  { ERREXIT1( cinfo, JERR_BAD_STATE, cinfo->global_state ); }
  ( *cinfo->marker->write_marker_header )( cinfo, marker, datalen );
  write_marker_byte = cinfo->marker->write_marker_byte;	/* copy for speed */
  while( datalen-- ) {
    ( *write_marker_byte )( cinfo, *dataptr );
    dataptr++;
  }
}

void jpeg_write_m_header( j_compress_ptr cinfo, int marker, unsigned int datalen ) {
  if( cinfo->next_scanline != 0 ||
      ( cinfo->global_state != CSTATE_SCANNING &&
        cinfo->global_state != CSTATE_RAW_OK &&
        cinfo->global_state != CSTATE_WRCOEFS ) )
  { ERREXIT1( cinfo, JERR_BAD_STATE, cinfo->global_state ); }
  ( *cinfo->marker->write_marker_header )( cinfo, marker, datalen );
}

void jpeg_write_m_byte( j_compress_ptr cinfo, int val ) {
  ( *cinfo->marker->write_marker_byte )( cinfo, val );
}


void jpeg_write_tables( j_compress_ptr cinfo ) {
  if( cinfo->global_state != CSTATE_START )
  { ERREXIT1( cinfo, JERR_BAD_STATE, cinfo->global_state ); }
  ( *cinfo->err->reset_error_mgr )( ( j_common_ptr ) cinfo );
  ( *cinfo->dest->init_destination )( cinfo );
  jinit_marker_writer( cinfo );
  ( *cinfo->marker->write_tables_only )( cinfo );
  ( *cinfo->dest->term_destination )( cinfo );
}
